﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using Shoozla.DataModel.Helper;
using System.Diagnostics;

namespace Shoozla.DataModel
{
    /// <summary>
    /// Scan a folder and read all the Mp3 file 
    /// </summary>
    public class FolderScanner : IProgressOperation
    {
        //interface implementation
        public int Minimum { get; set; }
        public int Maximum { get; set; }
        public int Current { get; set; }
        public String Description { get; set; }

        public event EventHandler<ProgressOperationEventArgs> ProgressChanged;
        public event EventHandler<ProgressOperationEventArgs> Completed;
        public event EventHandler<ProgressOperationEventArgs> Started;


        public DirectoryInfo Folder { get; private set; }

        public List<Mp3File> Mp3FileInFolder { get; private set; }
        private CancellationTokenSource _cancelToken;
        private IMP3Processor _mp3Processor;

        public FolderScanner(CancellationTokenSource cancelToken, IMP3Processor mp3Processor)
        {
            _cancelToken = cancelToken;
            _mp3Processor = mp3Processor;
            Mp3FileInFolder = new List<Mp3File>();
        }

        public void CancelAsync() { _cancelToken.Cancel(); }

        /// <summary>
        /// the folder will be scanned for Mp3
        /// </summary>
        /// <param name="folder">folder to scan</param>
        /// <returns>number of Mp3 file</returns>
        public int AddFolderToScanner(DirectoryInfo folder)
        {
            Folder = folder;
            Description = "Searching Mp3 files in " + folder.Name;
            Mp3FileInFolder.Clear();
            Maximum = Folder.GetFiles("*.mp3", SearchOption.TopDirectoryOnly).Count();
            return Maximum;
        }

        public void Start()
        {
            Task.Factory.StartNew((Action)(() =>
            {
                try
                {
                    if (Folder != null)
                    {
                        FileInfo[] files = Folder.GetFiles("*.mp3", SearchOption.TopDirectoryOnly);

                        if (files.Count() == 0) return;

                        Maximum = files.Count();
                        Minimum = 0;
                        Current = 0;

                        if (Started != null)
                            foreach (Delegate d in Started.GetInvocationList())
                            {
                                d.DynamicInvoke(new object[] { null, new ProgressOperationEventArgs(0, Maximum, Description) });
                            }

                        ParallelOptions paralleSettings = new ParallelOptions();
                        paralleSettings.CancellationToken = _cancelToken.Token;
                        paralleSettings.MaxDegreeOfParallelism = ThreadHelper.CalculateTreads(files.Count(), ThreadingFactorEnum.Maximum);
                        Parallel.ForEach(files, paralleSettings, f => FileReader(f));
                    }


                }
                catch (OperationCanceledException ce)
                {
                    //user interrupted the operation
                    Trace.WriteLine("[INFO] FolderScanner: Operation stopped");

                }
                catch (UnauthorizedAccessException accEx)
                {
                    Trace.WriteLine("[ERROR] OpenFolderInternal: " + accEx.Message);
                    //skip the directory
                    throw accEx; //this to display a message to the user
                }
                catch (Exception ex)
                {
                    Trace.WriteLine("[ERROR] OpenFolderInternal: " + ex.Message);
                }
                finally
                {
                    RaiseCompleted();
                }
            }));
        }

        private void RaiseCompleted() {

            if (Completed != null)
                foreach (Delegate d in Completed.GetInvocationList())
                {
                    d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Mp3FileInFolder.Count, Maximum, Description) });
                }
        }

        private void FileReader(FileInfo fi)
        {
            Mp3File song = _mp3Processor.ReadID3Tag(fi,false); //not reading images (to save memory)
            if (song != null)
            {
               // song.IsSelected = !song.HasCover; //select all "uncovered album"
                Mp3FileInFolder.Add(song);
                Current++;

                if (ProgressChanged != null)
                    foreach (Delegate d in ProgressChanged.GetInvocationList())
                    {
                        d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Mp3FileInFolder.Count, Maximum, Description) });

                    }
            }          
        }


    }
}
